$(function(){
    test = new Test();
    test.transitionInitialize();
    console.log("script.js ok");
});

Test = function () {
  $( "#sortable" ).disableSelection();
  
  $( "#learn" ).click(function() {
    fileName = test.getStartFileName();
    text = test.readFromFile(fileName);
    triplets = test.splitToTriplets(text);
    test.getStats(triplets);
    test.logHistory("uczenie zakończone na podstawie pliku: " + test.getStartFileName());
  });
  
  $( "#btnget" ).click(function() {
    test.convertSequenceFromGui();
  });
  
  $( "#test" ).click(function() {
      console.log("test");
      d= new Date();
      timeBegin = d.getTime();
      percentage = test.doTest();
      d= new Date();
      timeEnd = d.getTime();
      timeDif = timeEnd - timeBegin;
      mil = timeDif % 1000;
      timeDif -= mil;
      timeDif /=1000;
      sec = timeDif %60;
      timeDif -= sec;
      timeDif /= 60;
      min =timeDif;
      timeStr = "min.: "+min+" s.: "+sec+" ms.: "+mil;
      test.logHistory("prawidłowość testu: " + percentage);
      test.logHistory("czas: "+timeStr);
  });
  
  $( "#btntoggle" ).click(function() {
      test.doAuto = !test.doAuto;
  
      if (test.doAuto){
        $(this).css("border", '1px solid #ddd');
        test.convertSequenceFromGuiIfNeeded();
      }
      else{
        $(this).css("border", '1px solid #000');
      }
  });
  
  $( ".adder" ).click(function(event) {
      $( "#sortable" ).append('<li class="aminokwas" style="background-color: '+$(this).css("background-color")+'">'+$(this).text()+" </li>");
      test.convertSequenceFromGuiIfNeeded();
  });
  
  $(document).on('click', '.aminokwas', function() {
      $(this).remove();
      test.convertSequenceFromGuiIfNeeded();
  });	
  
  $( ".adder" ).each( function() {
      var str = ""
      $.each(res.emission[$(this).text().trim()], function(key, val){
        str = str + key + " ";
      });
      $(this).attr('title', str);
  });
  
  this.testFile = "test_files";
  this.startFile = "files";
  this.doAuto = false;
};

Test.prototype.convertSequenceFromGuiIfNeeded = function(){
  if(test.doAuto){
    this.convertSequenceFromGui();
  }
}

Test.prototype.convertSequenceFromGui = function(){
    var tempText = $("#sortable").text();
    tempText = tempText.replace(/\s+/g, " ").trim();
    var proteins = tempText.split(" ");;
    newTriplets = test.convertToTripletsViterbi(proteins);

    $( "#nonsortable" ).empty();
    var ktory = 0;
    $( "#sortable" ).children().each( function(event) {
        $( "#nonsortable" ).append('<li class="trojka" style="background-color: '+$(this).css("background-color")+'">'+newTriplets[ktory++]+"</li>");
     });
}

Test.prototype.readFromFile = function(fileName) {
    var request = new XMLHttpRequest(); 
    request.open("GET",fileName,false); 
    request.send(); 
    myTextFile = request.responseText; 
    myTextFile = myTextFile.replace(/\s/g,'');
    myTextFile = myTextFile.replace(/T/g, 'U');
    return myTextFile;
};

Test.prototype.convertFromT2U = function(triplet){
  if(triplet[0] == 'T'){
    triplet[0] = 'U';
  } 

  if(triplet[1] == 'T'){
    triplet[1] = 'U';
  }

  if(triplet[2] == 'T'){
    triplet[2] = 'U';
  }
};

Test.prototype.splitToTriplets = function(sequence) {
    var length = sequence.length/3;
    if(sequence.length %3 >0){
      length -= 1;
    }
    var triplets = [length];
    for (var i = 0; i < length ; ++i){
      triplets[i] = sequence.substring(i*3,(i+1)*3);
    }
    return triplets;
};

Test.prototype.goodGen = function(c){
  retValue = false;
  if(c == 'A' || c == 'G' || c == 'U' || c == 'C'){
    retValue = true;
  }
  return retValue;
};

Test.prototype.goodTriplet = function(triplet){
  retValue = false;
  if(triplet.length == 3){
    retValue = this.goodGen(triplet[0]) && this.goodGen(triplet[1]) && this.goodGen(triplet[2]);
  }
  return retValue;
}

Test.prototype.toProtein = function(triplet){
    protein = 'NONE'
    if(res.triplesToProteins[triplet] == undefined){
      if(this.goodTriplet(triplet)){
        console.log("error: no triplet "+ triplet);
      }
    }
    else{
      protein = res.triplesToProteins[triplet];
    }
    return protein; 
};

Test.prototype.splitToProteins = function(sequence){
    var length = sequence.length/3;
    proteins = [];
    for (var i = 0; i < length ; ++i){
      var triplet = sequence.substring(i*3,(i+1)*3);
      proteins[i] = this.toProtein(triplet);
    }
    return proteins;
};


Test.prototype.convertToProteins = function(triplets) {
    proteins = [];
    triplets.forEach(function(triplet){
        proteins.push(Test.prototype.toProtein(triplet));
    });
    return proteins;
};

Test.prototype.getMaxPropabilityTriplet = function(V, actualTriplet, actualTripletProb) {
    var maxProb = -1;
    var chosenTriplet;
   
    for (var previousTriplet in V){
          prob = V[previousTriplet] * res.transition[previousTriplet][actualTriplet] * actualTripletProb; 
          if (prob > maxProb){
            maxProb = prob;
            chosenTriplet = previousTriplet;
          }
    }
    return [maxProb, chosenTriplet];
};

Test.prototype.getMaxValue = function(map){
    var maxValue = -1;
    var retKey;
    for(var key in map){
       var val = map[key];
       if(val > maxValue){
           retKey = key;
           maxValue = val;
       }
    }
    return [maxValue, retKey];
};

Test.prototype.convertToTripletsViterbi = function(proteins) {
    V = {};
    Vp = [];
    path = {}; 
    startPropability = 1;

    $.each(res.emission[proteins[0]], function(key, val){
        V[key] = startPropability * val;
      });
    console.log(proteins.length);
    for(var i = 1; i < proteins.length; ++i){
        newV = {};
        Vp[i-1] = {};
        $.each(res.emission[proteins[i]], function(key, val){
          var prob;
          var previousTriplet;
          [prob, previousTriplet] = Test.prototype.getMaxPropabilityTriplet(V, key, val);
          if(prob !=0){
            newV[key] = prob;
            Vp[i-1][key] = previousTriplet;
          }
        });
        V = newV;
        if(i%10000 == 0){
          console.log(i);
        }
          var maxProb;
          var tripleKey;
          [maxProb, tripleKey] = this.getMaxValue(V);
          if(maxProb < 0.000001){
            for(var key1 in V){
              V[key1] *= 100000;
            }
          }
    }
    
    var tripleKey;
    var maxProb;
    [maxProb, tripleKey] = this.getMaxValue(V);
    pathV = [tripleKey];
    triple = tripleKey;
    for(var i = proteins.length - 2; i >=0; --i){
      triple = Vp[i][triple]
      pathV.push(triple);
    }
    return pathV.reverse();
};

Test.prototype.getStats = function(triplets){
    res.transition = {};
    stats = res.transition;
    for(var triplet in res.states){
        stats[res.states[triplet]] = {};
        for (var triplet2 in res.states){
            if(res.states[triplet2] == "NNN"){
              stats[res.states[triplet]][res.states[triplet2]] = 1;
            }
            else{
              stats[res.states[triplet]][res.states[triplet2]] = 0;
            }
            stats[res.states[triplet]]["size"] = 0;
        }
    }
    stats["size"] = 0;

    for ( var i =1; i < triplets.length; ++i){
      if(this.goodTriplet(triplets[i])){
        if(this.goodTriplet(triplets[i-1])){
          stats[triplets[i - 1]][triplets[i]] += 1;
          stats[triplets[i - 1]]["size"] += 1;
          stats["size"] += 1;
        }
        else{
          stats["NNN"][triplets[i]] +=1;
          stats["NNN"]["size"] +=1;
        }
      }
    }
    
    for(var triplet in stats){
        for (var triplet2 in stats){
            if(stats[triplet]["size"] != 0){
              stats[triplet][triplet2] = stats[triplet][triplet2]/stats[triplet]["size"];
            }
        }
    } 
};

Test.prototype.transitionInitialize = function(){
    res.transition = {};
    for(var triplet in res.states){
        res.transition[res.states[triplet]] = {};
        for (var triplet2 in res.states){
            if(res.states[triplet2] == "NNN"){
              res.transition[res.states[triplet]][res.states[triplet2]] = 1;
            }
            else{
              res.transition[res.states[triplet]][res.states[triplet2]] = 0;
            }
            res.transition[res.states[triplet]]["size"] = 0;
        }
    }
    res.transition["size"] = 0;
}

Test.prototype.getTestFileName = function(){
 return this.getFileName(this.testFile);
};

Test.prototype.getStartFileName = function(){
 return this.getFileName(this.startFile);
};

Test.prototype.getFileName = function(id){
  var files = document.getElementById(id).files;
  var retName = "";
  if (files.length > 0){
    retName = files[0].name
  }
  return retName;
};

Test.prototype.doTest = function(){
    fileName = this.getTestFileName();
    var positivesPerc = 0;
    if (fileName.length > 0){
      text = test.readFromFile(fileName);
      triplets = test.splitToTriplets(text);
      proteins = test.convertToProteins(triplets);
      newTriplets = test.convertToTripletsViterbi(proteins);
      positivesPerc = test.countPositives(triplets, newTriplets);
    }
    return positivesPerc;
};

Test.prototype.logHistory = function(log){
    $( "#coutput" ).append(">> " + log + "\n")
};

Test.prototype.countPositives = function(triplets, triplets2){
  var positivesCount = 0;
  var goodTripletsCount = 0;
  for(var i =0; i < triplets.length; ++i){
    if(this.goodTriplet(triplets[i])){
      if(triplets[i] == triplets2[i]){
        ++positivesCount;
      }
      ++goodTripletsCount;
    }
  }
  var percentage = positivesCount / goodTripletsCount;
  return percentage;
};
